﻿using DevExpress.XtraEditors;
using DevExpress.XtraGrid;
using DevExpress.XtraTreeList;
using DevExpress.XtraVerticalGrid;
using Inaction.Core;
using Inaction.Mapping;
using Inaction.Message;
using Inaction.UI.Common;
using Inaction.Util;
using System;
using System.Collections;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;

namespace Inaction.UI
{
    public partial class BarManager : DevExpress.XtraBars.BarManager
    {
        public void Query()
        {
            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
            watch.Start();
            foreach (var bindingInfo in BindingInfos.Where(p => p.IsRoot && p.InQuery))
            {
                if (bindingInfo == MasterBindingInfo) continue;
                Query(bindingInfo);
            }
            OperateState = BarManagerState.Browse;
            Query(MasterBindingInfo);
            ApplyFormRules();
            watch.Stop();
            ShowMessage("查询:" + watch.ElapsedMilliseconds + "ms");
            ShowCurrentSourceInfo();
        }
        private void Query(BindingInfo bindingInfo, bool isRefresh = false)
        {
            if (bindingInfo.CriteriaBindingSource != null)
            {
                bindingInfo.CriteriaBindingSource.EndEdit();
            }
            Type type = BindingHelper.GetListType(bindingInfo.BindingSource);
            Type itemType = BindingHelper.GetListItemType(bindingInfo.BindingSource);
            var args = new BarItemClickEventArgs(bindingInfo.BindingSource);
            if (Querying != null)
            {
                Querying(this, args);
            }
            if (args.Cancel) return;
            if (!args.Applied)
            {
                bindingInfo.BindingSource.DataSource = (IEntityList)Inaction.Proxy.Query(type, bindingInfo.Criteria, itemType);
            }
            if (Queryed != null)
            {
                Queryed(this, new BarItemClickedEventArgs(bindingInfo.BindingSource));
            }
        }
        private object AddNew(BindingInfo bindingInfo, bool raiseEvent = true)
        {
            if (!bindingInfo.AllowNew) return null;
            MasterBindingInfo.BindingSource.EndEdit();
            var args = new BarItemClickEventArgs(bindingInfo.BindingSource);
            if (raiseEvent)
            {
                if (AddNewing != null)
                {
                    AddNewing(this, args);
                }
            }
            if (args.Cancel) return null;
            object obj = null;
            if (!args.Applied)
            {
                if (bindingInfo.TypeIsList)
                {
                    obj = bindingInfo.EntityList.AddNew();
                    bindingInfo.BindingSource.Position = bindingInfo.BindingSource.IndexOf(obj);
                }
                else//单个对象新增
                {
                    var method = TypeHelper.GetStaticMethodInfo(bindingInfo.ItemType, "New", new Type[] { });
                    obj = method.Invoke(null, null);
                    bindingInfo.BindingSource.DataSource = obj;
                }
            }
            FocusedToFirstControl(bindingInfo);
            OperateState = BarManagerState.Modify;
            if (raiseEvent)
            {
                if (AddNewed != null)
                {
                    AddNewed(this, new BarItemClickedEventArgs(bindingInfo.BindingSource));
                }
            }
            ApplyFormRules();
            return obj;
        }
        public object AddNew(BindingSource bindingSource, bool raiseEvent = true)
        {
            MasterBindingInfo.BindingSource.EndEdit();
            var bindingInfo = BindingInfos.FirstOrDefault(p => p.BindingSource == bindingSource);
            if (bindingInfo == null)
            {
                throw new Exception("数据源未配置");
            }
            return AddNew(bindingInfo, raiseEvent);
        }
        private void Modify(BindingInfo bindingInfo, bool raiseEvent = true)
        {
            BarItemClickEventArgs args = new BarItemClickEventArgs(bindingInfo.BindingSource);
            if (Modifying != null)
            {
                Modifying(this, args);
            }
            if (args.Cancel) return;
            FocusedToFirstControl(bindingInfo);
            OperateState = BarManagerState.Modify;
            ApplyFormRules();
        }
        public void Modify(BindingSource bindingSource, bool raiseEvent = true)
        {
            var bindingInfo = BindingInfos.FirstOrDefault(p => p.BindingSource == bindingSource);
            if (bindingInfo == null)
            {
                throw new Exception("数据源未配置");
            }
            Modify(bindingInfo, raiseEvent);
        }
        public bool Save()
        {
            try
            {
                System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
                watch.Start();
                GetForm().ValidateChildren(ValidationConstraints.Enabled);
                foreach (var bindingInfo in BindingInfos)
                {
                    if (bindingInfo.BindingSource != null)
                        bindingInfo.BindingSource.EndEdit();
                }
                var args = new BarItemClickEventArgs(MasterBindingInfo.BindingSource);
                if (Saving != null)
                {
                    Saving(this, args);
                }
                var error = string.Empty;
                if (CheckError(out error))
                {
                    MessageHost.ShowMessage(error);
                    return false;
                }
                var firstTransBindings = BindingInfos.Where(p => p.IsRoot && p.TransDataType == TransDataType.FirstTransData);
                MasterBindingInfo.SavableObj.FirstTransData.AddRange(firstTransBindings.Select(p => p.BindingSource.List as ISavable));

                var lastTransBindings = BindingInfos.Where(p => p.IsRoot && p.TransDataType == TransDataType.LastTransData);
                MasterBindingInfo.SavableObj.LastTransData.AddRange(firstTransBindings.Select(p => p.BindingSource.List as ISavable));
                if (args.Cancel) return false;
                if (!args.Applied)
                {
                    if (MasterBindingInfo.EntityList != null)
                    {
                        MasterBindingInfo.EntityList.Save();
                    }
                    else
                    {
                        MasterBindingInfo.SavableObj.Save();
                    }
                }
                OperateState = BarManagerState.Browse;
                if (Saved != null)
                {
                    Saved(this, new BarItemClickedEventArgs(MasterBindingInfo.BindingSource));
                }
                ApplyFormRules();
                watch.Stop();
                ShowMessage("保存:" + watch.ElapsedMilliseconds + "ms");
                return true;
            }
            catch (Exception ex)
            {
                var innerException = ex.GetInnerException();
                if (innerException is Core.UniqueException)
                {
                    var exception = innerException as Core.UniqueException;
                    IEntity entity = null;
                    var temp = BindingInfos.Where(p => p.ItemType == exception.Type);
                    BindingInfo b = null;
                    if (temp.Count() == 1)
                    {
                        b = temp.First();
                        if (b.TypeIsList)
                        {
                            foreach (var item in b.EntityList)
                            {
                                if ((item as IEntity).PrimaryKey == exception.Id)
                                {
                                    entity = (IEntity)item;
                                    break;
                                }
                            }
                        }
                        else
                        {
                            if ((b.SavableObj as IEntity).PrimaryKey == exception.Id)
                            {
                                entity = b.SavableObj as IEntity;
                            }
                        }
                    }
                    else
                    {
                        foreach (var bindingInfo in temp)
                        {
                            if (bindingInfo.TypeIsList)
                            {
                                foreach (var item in bindingInfo.EntityList)
                                {
                                    if ((item as IEntity).PrimaryKey == exception.Id)
                                    {
                                        entity = (IEntity)item;
                                        bindingInfo.BindingSource.Position = bindingInfo.BindingSource.IndexOf(entity);
                                        b = bindingInfo;
                                        break;
                                    }
                                }
                                if (entity != null)
                                {
                                    break;
                                }
                            }
                            else
                            {
                                if ((bindingInfo.SavableObj as IEntity).PrimaryKey == exception.Id)
                                {
                                    entity = bindingInfo.SavableObj as IEntity;
                                    b = bindingInfo;
                                    break;
                                }
                            }
                        }
                    }
                    if (entity != null)
                    {
                        var classInfo = ClassInfo.LoadInfo(b.ItemType);
                        var columns = classInfo.Table.UniqueKeys.FirstOrDefault(p => p.Name == exception.UniqueName).Columns;
                        string message = string.Format(Inaction.Resource.Properties.Resources.UniqueKeyDataExists, classInfo.DisplayName, string.Join(",", columns.Select(p => p.DisplayName)));

                        if (b.TypeIsList)
                        {
                            b.BindingSource.Position = b.BindingSource.IndexOf(entity);
                        }
                        
                        ShowMessage(message);
                        if (formManager.BindingEditors.ContainsKey(b.BindingSource))
                        {
                            var properties = classInfo.MappedProperties.Where(p => columns.Any(t => t.Name.Equals(p.Value.Column.Name)));
                            foreach (BaseEdit edit in formManager.BindingEditors[b.BindingSource].Values)
                            {
                                var binding = edit.DataBindings.Cast<Binding>().FirstOrDefault(p => properties.Any(t => t.Value.Name.Equals(p.BindingMemberInfo.BindingField)));
                                if (binding != null)
                                {
                                    edit.ErrorText = message;
                                }
                            }
                        }
                    }
                    return false;
                }
                else
                {
                    throw;
                }
            }
        }
        private void Delete(BindingInfo bindingInfo)
        {
            if (bindingInfo.BindingSource.Current == null) return;
            var args = new BarItemClickEventArgs(bindingInfo.BindingSource);
            if (Deleting != null)
            {
                Deleting(this, args);
                if (args.Cancel) return;
            }
            var error = string.Empty;
            var current = bindingInfo.BindingSource.Current as Inaction.Business.IEntity;
            if (current.CheckExistsForeignKeyChildrenData(ref error))
            {
                ShowMessage(error);
                MessageHost.ShowMessage(error);
                return;
            }

            (bindingInfo.SavableObj as IList).Remove(bindingInfo.BindingSource.Current);
            if (Deleted != null)
            {
                Deleted(this, new BarItemClickedEventArgs(bindingInfo.BindingSource));
            }
        }
        public void Delete(BindingSource bindingSource)
        {
            var bindingInfo = BindingInfos.FirstOrDefault(p => p.BindingSource == bindingSource);
            if (bindingInfo == null)
            {
                throw new Exception("数据源未配置");
            }
            Delete(bindingInfo);
        }
        private void Cancel()
        {
            foreach (var bindingInfo in BindingInfos.Where(p => p.IsRoot))
            {
                if (bindingInfo.SavableObj != null)
                {
                    var args = new BarItemClickEventArgs(bindingInfo.BindingSource);
                    if (Canceling != null)
                    {
                        Canceling(this, args);
                    }
                    bindingInfo.SavableObj.CancelEdit();
                    bindingInfo.BindingSource.ResetBindings(false);
                    if (Canceled != null)
                    {
                        Canceled(this, new BarItemClickedEventArgs(bindingInfo.BindingSource));
                    }
                }
                SetEditorsReadOnly(true, bindingInfo);
            }
            CurrentBindingInfo = MasterBindingInfo;
            OperateState = BarManagerState.Browse;
            ApplyFormRules();
            GetForm().ValidateChildren(ValidationConstraints.Enabled);
        }
        private void Export()
        {
            if (Exporting != null)
            {
                Exporting();
            }
            else
            {
                if (focusedEditorContainer == null) return;
                Common.ControlHelper.ExportToExcelFile(focusedEditorContainer);
            }
        }
        private void Print()
        {
            if (Printing != null)
                Printing();
        }
        public bool HasPrintAction { get { return Printing != null; } }
        private void Help()
        {
            if (Helping != null) Helping(this, new HelpEventArgs { Key = Form.GetType().FullName });
        }
        private void FocusedToFirstControl(BindingInfo bindingInfo)
        {
            if (bindingInfo != null && FormManager.BindingEditors.ContainsKey(bindingInfo.BindingSource))
            {
                FormManager.BindingEditors[bindingInfo.BindingSource].FirstEditor.Focus();
            }
        }
    }
}